package com.iteaj.iot.server.component;

import com.iteaj.iot.*;
import com.iteaj.iot.codec.SocketMessageDecoder;
import com.iteaj.iot.config.ConnectProperties;
import com.iteaj.iot.server.DeviceServerComponent;
import com.iteaj.iot.server.IotSocketServer;
import com.iteaj.iot.server.ServerMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelPipeline;
import org.springframework.beans.BeanUtils;
import org.springframework.core.GenericTypeResolver;

import java.lang.reflect.Constructor;

/**
 * create time: 2021/2/20
 *
 * @author iteaj
 * @since 1.0
 */
public abstract class SocketDecoderComponent<M extends ServerMessage> extends DeviceServerComponent
        implements IotSocketServer, IotProtocolFactory<M>, SocketMessageDecoder<M, ByteBuf> {

    private Class<M> messageClass;
    private Constructor<M> constructor;
    private ConnectProperties connectProperties;
    private ProtocolFactoryDelegation delegation;

    public SocketDecoderComponent(ConnectProperties connectProperties) {
        this.connectProperties = connectProperties;
        this.delegation = new ProtocolFactoryDelegation(this, protocolTimeoutStorage());
    }

    @Override
    public abstract String getName();

    @Override
    public int port() {
        return this.connectProperties.getPort();
    }

    @Override
    public ConnectProperties config() {
        return this.connectProperties;
    }

    @Override
    protected IotSocketServer createDeviceServer() {
        return this;
    }

    @Override
    protected IotProtocolFactory createProtocolFactory() {
        return this;
    }

    @Override
    public void init(Object... args) {
        this.doInitChannel((ChannelPipeline) args[0]);
    }

    @Override
    public M createMessage(byte[] message) {
        try {
            if(this.constructor == null) {
                this.constructor = this.messageClass.getConstructor(byte[].class);
            }

            return BeanUtils.instantiateClass(this.constructor, message);
        } catch (NoSuchMethodException e) {
            throw new ProtocolException("没有匹配的构造函数", e);
        }
    }

    @Override
    public Class<M> getMessageClass() {
        if(this.messageClass == null) {
            this.messageClass = (Class<M>) GenericTypeResolver
                    .resolveTypeArgument(getClass(), SocketDecoderComponent.class);
        }

        return this.messageClass;
    }

    @Override
    public AbstractProtocol get(String key) {
        return this.delegation.get(key);
    }

    @Override
    public AbstractProtocol add(String key, Protocol val) {
        return this.delegation.add(key, val);
    }

    @Override
    public AbstractProtocol add(String key, Protocol protocol, long timeout) {
        return this.delegation.add(key, protocol, timeout);
    }

    @Override
    public AbstractProtocol remove(String key) {
        return this.delegation.remove(key);
    }

    @Override
    public boolean isExists(String key) {
        return this.delegation.isExists(key);
    }

    @Override
    public Object getStorage() {
        return this.delegation.getStorage();
    }

}
